﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Threading;
using System.Threading.Tasks;
using FXC.Web.Entity;
using FXC.Web.Utility;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
using System.Diagnostics;

namespace FXC.Web.Service
{
    [ServiceContract(CallbackContract = typeof (ISendInstantMessageServiceCallBack))]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
    public class FXCService
    {
        private readonly FXDataCenterEntities context = new FXDataCenterEntities();

        private readonly GetFXContent fxContent = new GetFXContent();

        private readonly List<FXClient> listFXClient = new List<FXClient>();

        public object LockObject = new object();

        private Timer listenTimer;
        //private ServiceStatus serviceStatus = ServiceStatus.Stopped;

        private FXCService()
        {
        }

        [OperationContract]
        public bool GetMessage()
        {
            bool bRet = true;
            var currCallBack = OperationContext.Current.GetCallbackChannel<ISendInstantMessageServiceCallBack>();

            if (!listFXClient.Any(a=>a.CallBack == currCallBack))
            {
                FXClient client = new FXClient();
                client.CallBack = currCallBack;
                client.AttemptCount = 0;

                listFXClient.Add(client);
            }

            if (listenTimer == null)
            {
                listenTimer = new Timer(SendMessageToClient, this, StaticData.SendMessageInterval,
                                        Timeout.Infinite);
            }

            return bRet;
        }

        [OperationContract]
        public void Quit()
        {
            var currCallBack = OperationContext.Current.GetCallbackChannel<ISendInstantMessageServiceCallBack>();
            if (listFXClient.Any(a => a.CallBack == currCallBack))
            {
                listFXClient.Remove(listFXClient.Where(a => a.CallBack == currCallBack).FirstOrDefault());
            }
        }

        //[OperationContract]
        //public List<FXProduct> GetProductList()
        //{
        //    return (from c in context.FXProducts select c).ToList();
        //}

        [OperationContract]
        public List<FXData> GetFXCData(string productCode, string fxType)
        {
            var a = from c in context.FXDatas
                                    where c.FXProductCode == productCode && c.FXType == fxType
                                    select c;
            int b = a.Count();
            return a.OrderByDescending(o => o.ProcessDateTime).Take(500).ToList();
        }

        

        private void notice_exceptionDelegate(FXClient client)
        {

            lock (LockObject)
            {
                if (client != null)
                {
                    if (listFXClient.Contains(client) && client.AttemptCount > 10)
                    {
                        listFXClient.Remove(client);
                    }
                }
            }
        }

        private void SendMessageToClient(object sender)
        {
            string strMessage = fxContent.GetFXContentValue();

            foreach (FXClient fxClient in listFXClient)
            {
                ISendInstantMessageServiceCallBack callBack = fxClient.CallBack;
                try
                {
                    //异步处理
                    //callBack.BeginReceiveMessage(strMessage, result => {  }, null);
                    //同步处理

                    FXMessage notice = new FXMessage();
                    notice.exceptionDelegate += new ExceptionDelegate(notice_exceptionDelegate);
                    notice.Message = strMessage;
                    notice.Client = fxClient;
                    notice.SendMessageToClient();
                }
                catch (CommunicationObjectAbortedException ex)
                {
                    var exManager = EnterpriseLibraryContainer.Current.GetInstance<ExceptionManager>();

                    exManager.HandleException(ex, "Final Policy");

                    continue;
                    //listCallback.Remove(callBack);
                    //if (listCallback.Count == 0)
                    //{
                    //    break;
                    //}
                    //else
                    //{
                    //    continue;
                    //}
                }
                catch (TimeoutException ex)
                {
                    var exManager = EnterpriseLibraryContainer.Current.GetInstance<ExceptionManager>();

                    exManager.HandleException(ex, "Final Policy");

                    continue;

                    //listCallback.Remove(callBack);
                    //if (listCallback.Count == 0)
                    //{
                    //    break;
                    //}
                    //else
                    //{
                    //    continue;
                    //}
                }
                catch (Exception ex)
                {
                    var exManager = EnterpriseLibraryContainer.Current.GetInstance<ExceptionManager>();

                    exManager.HandleException(ex, "Final Policy");

                    //listCallback.Remove(callBack);

                    continue;
                }
            }

            listenTimer.Change(StaticData.SendMessageInterval, Timeout.Infinite);
        }
    }

    public interface ISendInstantMessageServiceCallBack
    {
        [OperationContract(IsOneWay = true, Name = "ReceiveMessage")]
        void ReceiveMessage(string instantMessage);

        [OperationContract(AsyncPattern =true, Name="ReceiveMessage", IsOneWay=true)]
        IAsyncResult BeginReceiveMessage(string instantMessage, System.AsyncCallback callback, object asyncState);

        void EndReceiveMessage(IAsyncResult result);
    }

    public delegate void ExceptionDelegate(FXClient client);

    public class FXMessage
    {
        private Thread noticeThread;

        public FXClient Client { get; set; }
        public string Message { get; set; }

        public event ExceptionDelegate exceptionDelegate;

        public FXMessage()
        {
            noticeThread = new Thread(new ThreadStart(SendMessage));
        }

        public void SendMessageToClient()
        {
            noticeThread.Start();
        }

        private void SendMessage()
        {
            try
            {
                Client.CallBack.ReceiveMessage(Message);
                Client.AttemptCount = 0;
            }
            catch (Exception ex)
            {
                var exManager = EnterpriseLibraryContainer.Current.GetInstance<ExceptionManager>();

                exManager.HandleException(ex, "Final Policy");

                if (exceptionDelegate != null)
                {
                    Client.AttemptCount++;

                    exceptionDelegate.Invoke(Client);
                }
            }
        }
    }

    public class FXClient
    {
        //以后要能会有很多信息，比如IP，时间等等
        //现在只有Callback和Attempt次数

        public ISendInstantMessageServiceCallBack CallBack
        {
            get;
            set;
        }
        public int AttemptCount
        {
            get;
            set;
        }
    }
}
